package com.youlu.campus.web.common.utils;


import lombok.extern.slf4j.Slf4j;

import java.sql.Timestamp;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.ParsePosition;
import java.text.SimpleDateFormat;
import java.time.DayOfWeek;
import java.time.Instant;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.SimpleTimeZone;

/**
 * 日期工具类
 */
@Slf4j
public class DateTimeUtils {

    public static final SimpleDateFormat FORMATER = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
    public static final SimpleDateFormat NOSFORMATER = new SimpleDateFormat("yyyy-MM-dd HH:mm");


    /**
     * 获取上个月开始时间 yyyy-MM-01 00:00:00
     *
     * @return
     */
    public static String queryUpMonthStartDate() {
        Calendar cal = Calendar.getInstance();
        cal.add(Calendar.MONTH, -1);
        cal.set(Calendar.DAY_OF_MONTH, 1);
        cal.set(Calendar.HOUR_OF_DAY, 0);
        cal.set(Calendar.MINUTE, 0);
        cal.set(Calendar.SECOND, 0);
        Date date = cal.getTime();
        return (formatDate(date, "yyyy-MM-dd HH:mm:ss"));
    }

    public static String getMondayOfThisWeek() {
        SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd");
        ParsePosition pos = new ParsePosition(0);
        Date strtodate = formatter.parse("2019-02-24", pos);
        //String strDate = getFormatDate("2019-02-23","yyyy-MM-dd");
        Date date = strtodate;
        Instant instant1 = date.toInstant();
        ZoneId zone = ZoneId.systemDefault();
        LocalDate today = LocalDateTime.ofInstant(instant1, zone).toLocalDate();
        LocalDate toweekMonday = today.with(DayOfWeek.FRIDAY);
        //today.compareTo()
        Instant instant = toweekMonday.atStartOfDay().atZone(zone).toInstant();
        return formatDate(Date.from(instant), "yyyy-MM-dd HH:mm:ss");
    }

    /**
     * 结算佣金
     *
     * @param settleDate 结算时间
     * @return
     */
    public static Date getSettleDeposit(Date settleDate) {
        Instant instant = settleDate.toInstant();
        ZoneId zone = ZoneId.systemDefault();
        LocalDate now = LocalDateTime.ofInstant(instant, zone).toLocalDate();
        now = now.plusDays(21L);
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
        String strFridayDate = now.format(formatter) + " 23:59:59";
        SimpleDateFormat formatter2 = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        ParsePosition pos = new ParsePosition(0);
        return formatter2.parse(strFridayDate, pos);
    }

    /**
     * 获取每周周五日期
     *
     * @return
     */
    public static Date getSettleFriday() {
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
        LocalDate friday = getFriday();
        String strFridayDate = friday.format(formatter) + " 23:59:59";
        SimpleDateFormat formatter2 = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        ParsePosition pos = new ParsePosition(0);
        return formatter2.parse(strFridayDate, pos);
    }

    private static LocalDate getFriday() {
        //当前日期
        LocalDate now = LocalDate.now();
        //获取周五
        LocalDate friday = now.with(DayOfWeek.FRIDAY);
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
        if (now.isAfter(friday)) {
            //获取周六
            LocalDate saturday = now.with(DayOfWeek.SATURDAY);
            //判断是否等于周六
            if (now.format(formatter).equals(saturday.format(formatter))) {
                now = now.plusDays(2L);
                return now.with(DayOfWeek.FRIDAY);
            }
            //获取周日
            LocalDate sunday = now.with(DayOfWeek.SUNDAY);
            //判断是否等于周日
            if (now.format(formatter).equals(sunday.format(formatter))) {
                now = now.plusDays(1L);
                return now.with(DayOfWeek.FRIDAY);
            }
        }
        return friday;
    }


    /**
     * 获取当前时间到指定时刻前的毫秒数
     *
     * @param hour 指定时刻的小时
     * @param min  指定时刻的分钟
     * @param sec  指定时刻的秒
     * @param mill 指定时刻的毫秒
     * @return
     */
    public static long getMillsecBeforeMoment(int hour, int min, int sec, int mill) {
        return getMillisecBetweenDate(new Date(), getMoment(hour, min, sec, mill));
    }


    /**
     * 获取两个日期之间的毫秒数
     *
     * @param before
     * @param after
     * @return
     */
    public static long getMillisecBetweenDate(Date before, Date after) {
        long beforeTime = before.getTime();
        long afterTime = after.getTime();
        return afterTime - beforeTime;
    }

    /**
     * 获取当天的某一时刻Date
     *
     * @param hour 24小时
     * @param min  分钟
     * @param sec  秒
     * @param mill 毫秒
     * @return
     */
    public static Date getMoment(int hour, int min, int sec, int mill) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(new Date());
        calendar.set(Calendar.HOUR_OF_DAY, hour);
        calendar.set(Calendar.MINUTE, min);
        calendar.set(Calendar.SECOND, sec);
        calendar.set(Calendar.MILLISECOND, mill);
        return calendar.getTime();
    }


    /**
     * yyyyMMdd
     *
     * @param date
     * @return
     */
    public static String formatDate(Date date) {
        return (formatDate(date, "yyyy-MM-dd"));
    }

    /**
     * yyyyMMdd
     *
     * @param date
     * @return
     */
    public static String formatTime(Date date) {
        return (formatDate(date, "HHmmss"));
    }

    /**
     * 按照指定的格式返回日期字符串. 默认 "yyyy-MM-dd"
     *
     * @param
     */
    public static String formatDate(String pattern) {
        Date d = new Date();
        if (pattern == null)
            pattern = "yyyy-MM-dd";
        SimpleDateFormat sdf = new SimpleDateFormat(pattern);
        return (sdf.format(d));
    }

    /**
     * 按照指定的格式返回日期字符串. 默认 "yyyy-MM-dd"
     *
     * @param date
     * @param pattern
     * @return
     */
    public static String formatDate(Date date, String pattern) {
        if (date == null) return "";
        if (pattern == null) pattern = "yyyy-MM-dd";
        SimpleDateFormat sdf = new SimpleDateFormat(pattern);
        return (sdf.format(date));
    }

    /**
     * yyyy-MM-dd HH:mm:ss
     *
     * @param date
     * @return
     */
    public static String formatDateTime(Date date) {
        return (formatDate(date, "yyyy-MM-dd HH:mm:ss"));
    }

    /**
     * 返回 yyyyMMddHHmmss 格式的当前日期字符串
     *
     * @return String
     */
    public static String getDate() {
        String s = null;
        Date d = new Date();
        SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmss");
        s = sdf.format(d);
        return s;
    }

    public static String getDate2() {
        String s = null;
        Date d = new Date();
        SimpleDateFormat sdf = new SimpleDateFormat("MMddHHmmss");
        s = sdf.format(d);
        return s;
    }

    /**
     * 返回 yyyyMMddHHmmssSSS 格式的当前日期字符串
     *
     * @return String
     */
    public static String getDateTime() {
        String s = null;
        Date d = new Date();
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");
        s = sdf.format(d);
        return s;
    }

    /**
     * 返回 yyyy-MM-dd HH:mm:ss 格式的当前日期字符串
     *
     * @return String
     */
    public static String getDateTimeStr() {
        Date d = new Date();
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        return sdf.format(d);
    }

    /**
     * 返回 yyyyMMddHHmmssSSS 格式的字符串
     *
     * @return String
     */
    public static String getDateTime(long n) {
        String s = null;
        Date d = new Date(n);
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");
        s = sdf.format(d);
        return s;
    }

    public static String turnFormat(String date, DateFormat format, DateFormat toFomrat) {
        String toString = date;
        try {
            toString = toFomrat.format(format.parse(date));
        } catch (Exception e) {
            log.warn("turnFormat()异常：{}", e);
        }
        return toString;
    }

    public static long getTime(String str) {
        long time = 0l;
        if (str == null)
            return time;
        try {
            time = FORMATER.parse(str).getTime();
            if (time == 0)
                time = NOSFORMATER.parse(str).getTime();
        } catch (Exception e) {
            log.warn("getTime()异常：{}", e);
        }
        return time;
    }

    /**
     * 时间字符串转化为timestamp
     *
     * @param times
     * @return
     */
    public static Timestamp stringToTimestamp(String times) {
        Timestamp ts = new Timestamp(System.currentTimeMillis());
        try {
            ts = Timestamp.valueOf(times);
        } catch (Exception e) {
            log.warn("时间字符串转化为timestamp异常：{}", e);
        }
        return ts;
    }

    public static String timesstampToString() {
        Timestamp ts = new Timestamp(System.currentTimeMillis());
        String tsStr = "";
        DateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        try {
            //方法一  
            tsStr = sdf.format(ts);
        } catch (Exception e) {
            log.warn("timestamp转化为时间字符串异常：{}", e);
        }
        return tsStr;
    }


    public static String getDayDate() {
        String s = null;
        Date d = new Date();
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
        s = sdf.format(d);
        return s;
    }

    /**
     * 获取年月
     *
     * @param date
     * @param dateformat
     * @return
     */
    public static String getYearMonth(Date date, String dateformat) {
        SimpleDateFormat dd = new SimpleDateFormat(dateformat);
        return dd.format(date);
    }

    /**
     * 字符串转日期
     *
     * @param dateStr
     * @param dateformat
     * @return
     */
    public static Date StringToDate(String dateStr, String dateformat) {
        SimpleDateFormat dd = new SimpleDateFormat(dateformat);
        Date date = null;
        try {
            date = dd.parse(dateStr);
        } catch (ParseException e) {
            log.warn("字符串转日期异常：{}", e);
        }
        return date;
    }

    /**
     * 字符串转日期
     *
     * @param dateStr
     * @return
     */
    public static Date StringToDate(String dateStr) {
        SimpleDateFormat dd = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        Date date = null;
        try {
            date = dd.parse(dateStr);
        } catch (ParseException e) {
            log.warn("字符串转日期异常：{}", e);
        }
        return date;
    }

    /**
     * get time(one hour,one day,one week)
     *
     * @param n
     * @return
     */
    public static String getPastTime(int n) {
        Date date = new Date(System.currentTimeMillis());
        SimpleDateFormat df = new SimpleDateFormat("yyyyMMddHHmmss");
        String dt = df.format(date);
        date = new Date(System.currentTimeMillis() - n * 60 * 60 * 1000);
        dt = df.format(date);
        return dt;
    }

    public static String getPastTime(Date date) {
        SimpleDateFormat df = new SimpleDateFormat("yyyyMMdd");
        String dt = df.format(date);
        return dt;
    }

    /**
     * get time(one hour,one day,one week)
     *
     * @param n
     * @return
     */
    public static String getPastTimeByDay(int n) {
        Date date = new Date(System.currentTimeMillis());
        SimpleDateFormat df = new SimpleDateFormat("yyyyMMdd");
        String dt = df.format(date);
        date = new Date(System.currentTimeMillis() - n * 60 * 60 * 1000);
        dt = df.format(date);
        return dt;
    }

    /**
     * function get the days of one year
     *
     * @return days
     */
    public static boolean getLeapYear() {
        boolean tag = false;
        Date date = new Date();
        SimpleDateFormat df = new SimpleDateFormat("yyyy");
        String dt = df.format(date);
        int pastYear = Integer.parseInt(dt) - 1;
        if (pastYear % 4 == 0 && (pastYear % 100 != 0 || pastYear % 400 == 0)) tag = true;
        return tag;
    }

    /**
     * @param days
     * @return
     */
    public static String decDays(int days) {
        String dateStr = null;
        Date date = new Date();
        Date dt = add(date, days, Calendar.DATE);
        SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd");
        dateStr = df.format(dt);
        return dateStr;
    }

    /**
     * function get pastyear date
     *
     * @return date
     */
    public static String getPastYearDate() {
        String dateStr = null;
        if (getLeapYear()) {
            dateStr = decDays(-366);
        } else {
            dateStr = decDays(-365);
        }
        return dateStr;
    }

    /**
     * 给时间加上或减去指定毫秒，秒，分，时，天、月或年等，返回变动后的时间
     *
     * @param date   要加减前的时间，如果不传，则为当前日期
     * @param field  时间域，有Calendar.MILLISECOND,Calendar.SECOND,Calendar.MINUTE,<br>
     *               Calendar.HOUR,Calendar.DATE, Calendar.MONTH,Calendar.YEAR
     * @param amount 按指定时间域加减的时间数量，正数为加，负数为减。
     * @return 变动后的时间
     */
    public static Date add(Date date, int amount, int field) {
        if (date == null) {
            date = new Date();
        }
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        calendar.add(field, amount);
        return calendar.getTime();
    }

    /**
     * 获取前n分钟的系统时间
     *
     * @param n 单位分钟
     * @return
     */
    public static String getBeforeMinute(int n) {
        Date now = new Date(System.currentTimeMillis());
        Date now_before_10 = new Date(now.getTime() - 60000 * n);
        SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        String dt = dateFormat.format(now_before_10);
        return dt;
    }

    /**
     * 获取前n分钟的系统时间
     *
     * @param now 当前系统时间
     * @param n
     * @return
     */
    public static String getBeforeMinute(Date now, int n) {
        Date now_before_10 = new Date(now.getTime() - 60000 * n);
        SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        String dt = dateFormat.format(now_before_10);
        return dt;
    }

    /**
     * function format time
     *
     * @param str
     * @return
     */
    public static String getFormatDate(String str) {
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
        Date date = null;
        String dateStr = null;
        try {
            date = sdf.parse(str);
            dateStr = sdf.format(date).replaceAll("-", "");
        } catch (ParseException e) {
            log.warn("获取yyyy-MM-dd时间字符串格式异常：{}", e);
        }

        return dateStr;
    }

    /**
     * function format time
     *
     * @param str
     * @return
     */
    public static String getFormatDate(String str, String format) {
        SimpleDateFormat sdf = new SimpleDateFormat(format);
        Date date = null;
        String dateStr = null;
        try {
            date = sdf.parse(str);
            dateStr = sdf.format(date);
        } catch (ParseException e) {
            log.warn("获取yyyy-MM-获取指定格式的时间字符串异常：{}", e);
        }

        return dateStr;
    }

    /**
     * 得到某年某月的第一天
     *
     * @param year
     * @param month
     * @return
     */
    public static String getFirstDayOfMonth(int year, int month) {

        Calendar cal = Calendar.getInstance();
        cal.set(Calendar.YEAR, year);
        cal.set(Calendar.MONTH, month - 1);
        cal.set(Calendar.DAY_OF_MONTH, cal.getMinimum(Calendar.DATE));
        return new SimpleDateFormat("yyyy-MM-dd").format(cal.getTime());
    }

    /**
     * 得到某年某月的最后一天
     *
     * @param year
     * @param month
     * @return
     */
    public static String getLastDayOfMonth(int year, int month) {

        Calendar cal = Calendar.getInstance();
        cal.set(Calendar.YEAR, year);
        cal.set(Calendar.MONTH, month - 1);
        cal.set(Calendar.DAY_OF_MONTH, 1);
        int value = cal.getActualMaximum(Calendar.DAY_OF_MONTH);
        cal.set(Calendar.DAY_OF_MONTH, value);
        return new SimpleDateFormat("yyyy-MM-dd").format(cal.getTime());

    }

    /**
     * 获取年月
     *
     * @return
     */
    public static String getYearMonth(String datestr) {
        Date date = StringToDate(datestr, "yyy-MM-dd");
        return getYearMonth(date, "yyyy-MM");
    }

    public static Boolean yearDateDiff(Date formDate) {
        Calendar calBegin = Calendar.getInstance(); //获取日历实例
        Calendar calEnd = Calendar.getInstance();
        calBegin.setTime(formDate);
        calEnd.setTime(new Date());
        int year = calEnd.get(Calendar.YEAR) - calBegin.get(Calendar.YEAR);
        //年份大于10年
        if (year > 10) {
            return true;
        }
        //年份相等10年，月份比当前月份小
        if (year == 10) {
            int month = calEnd.get(Calendar.MONTH) - calBegin.get(Calendar.MONTH);
            if (month >= 0) {
                return true;
            }
        }
        return false;
    }


    public static Date addDay(Date date, int amount) {
        return add(date, amount, Calendar.DATE);
    }

    public static Date addMonth(Date date, int amount) {
        return add(date, amount, Calendar.MONTH);
    }

    public static Date addYear(Date date, int amount) {
        return add(date, amount, Calendar.YEAR);
    }


    /**
     * @param end-begin
     * @return 两个日期之间相差的天数
     * @author wujt
     * @create 2018/3/5 上午10:27
     **/
    public static long getDaysBetween(Date begin, Date end) {

        Instant instant1 = begin.toInstant();
        ZoneId zone = ZoneId.systemDefault();
        LocalDateTime localDateTime = LocalDateTime.ofInstant(instant1, zone);
        LocalDate localDateBegin = localDateTime.toLocalDate();

        Instant instant2 = end.toInstant();
        LocalDateTime localDateTimeEnd = LocalDateTime.ofInstant(instant2, zone);
        LocalDate localDateEnd = localDateTimeEnd.toLocalDate();
        return localDateEnd.toEpochDay() - localDateBegin.toEpochDay();
    }

    /**
     * 获取日期距今的月份数
     *
     * @param date
     * @return
     */
    public static int getFormNowMonth(Date date) {
        int result = 0;

        Calendar calBegin = Calendar.getInstance(); //获取日历实例
        Calendar calEnd = Calendar.getInstance();
        calBegin.setTime(date);
        calEnd.setTime(new Date());

        int year = calEnd.get(Calendar.YEAR) - calBegin.get(Calendar.YEAR);

        result = year * 12 + (calEnd.get(Calendar.MONTH) - calBegin.get(Calendar.MONTH));

        return result <= 0 ? 0 : result;
    }

    /**
     * 获取日期的最大时间
     *
     * @param date
     * @return
     */
    public static Date getMaxTimeByday(Date date) {
        Calendar calendar = Calendar.getInstance(); //获取日历实例
        calendar.setTime(date);

        calendar.set(Calendar.HOUR_OF_DAY, 23);
        calendar.set(Calendar.MINUTE, 59);
        calendar.set(Calendar.SECOND, 59);
        return calendar.getTime();
    }


    public static String getYesterday() {
        Calendar cal = Calendar.getInstance();
        cal.add(Calendar.DATE, -1);
        String date = formatDate(cal.getTime(), "yyyy-MM-dd");
        return date + " 00:00:00" + "_" + date + " 23:59:59";
    }


    public static long getLongDate(Date date) {
        return new Long(formatDate(date, "yyyyMMdd"));
    }

    /**
     * 获取本月第一天时间
     *
     * @returna
     */
    public static Date getThisMonthFirstDayTime() {
        Calendar cal = Calendar.getInstance();
        cal.set(Calendar.DAY_OF_MONTH, 1);
        return cal.getTime();
    }

    /**
     * 获取指定时间的开始结束时间
     *
     * @return
     */
    public static DateContainer getStartEndTime(Date date) {
        Calendar cal = Calendar.getInstance();
        cal.setTime(date);
        DateContainer dateContainer = new DateContainer();
        dateContainer.setStartTime(getStartDate(cal));
        dateContainer.setEndTime(getEndDate(cal));
        return dateContainer;
    }

    /**
     * 获取今天开始结束时间
     *
     * @return
     */
    public static DateContainer getTodayStartEndTime() {
        Calendar cal = Calendar.getInstance();
        DateContainer dateContainer = new DateContainer();
        dateContainer.setStartTime(getStartDate(cal));
        dateContainer.setEndTime(getEndDate(cal));
        return dateContainer;
    }

    /**
     * 获取昨天开始结束时间
     *
     * @return
     */
    public static DateContainer getYesterdayStartEndTime() {
        Calendar cal = Calendar.getInstance();
        cal.add(Calendar.DATE, -1);
        DateContainer dateContainer = new DateContainer();
        dateContainer.setStartTime(getStartDate(cal));
        dateContainer.setEndTime(getEndDate(cal));
        return dateContainer;
    }

    public static Date getStartDate(Calendar cal) {
        Calendar calTemp = Calendar.getInstance();
        calTemp.setTime(cal.getTime());
        calTemp.add(Calendar.DATE, -1);
        calTemp.set(Calendar.HOUR_OF_DAY, 23);
        calTemp.set(Calendar.MINUTE, 59);
        calTemp.set(Calendar.SECOND, 59);
        return calTemp.getTime();
    }

    public static Date getEndDate(Calendar cal) {
        Calendar calTemp = Calendar.getInstance();
        calTemp.setTime(cal.getTime());
        calTemp.set(Calendar.HOUR_OF_DAY, 23);
        calTemp.set(Calendar.MINUTE, 59);
        calTemp.set(Calendar.SECOND, 59);
        return calTemp.getTime();
    }

    /**
     * 日期转换:日期查询isodate
     *
     * @param date
     * @return
     */
    public static Date dateToISODate(Date date) {
        log.info(">>> dateToISODate with date:{}", date);
        //T代表后面跟着时间，Z代表UTC统一时间
        SimpleDateFormat format =
                new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'");
        format.setCalendar(new GregorianCalendar(new SimpleTimeZone(0, "GMT")));
        String isoDate = format.format(date);
        try {
            return format.parse(isoDate);
        } catch (ParseException e) {
            log.error(":>>> 转换时间偶误:{}", e);
        }
        return null;
    }

    /**
     * 获取当天0点时间，需要服务器时统服务器
     *
     * @return
     */
    public static String getDay0Str() {
        Date zero = getDay0Date();
        //格式化日期
        SimpleDateFormat s = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        //转为字符串
        String dateStr = s.format(zero);
        return dateStr;

    }

    /**
     * 获取当天0点时间，需要服务器时统服务器
     *
     * @return
     */
    public static Date getDay0Date() {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(new Date());
        calendar.set(Calendar.HOUR_OF_DAY, 0);
        calendar.set(Calendar.MINUTE, 0);
        calendar.set(Calendar.SECOND, 0);
        Date zero = calendar.getTime();
        return zero;

    }

    public static void main(String[] args) {

        //System.out.println(isDigit("12A444"));
        Date date1 = StringToDate("2020-12-29", "yyyy-MM-dd");
        Date date2 = StringToDate("2020-12-31", "yyyy-MM-dd");
        System.out.println(getDaysBetween(date1,date2));
    }
}
